package com.arpa.wms.controller.wms;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.Page;
import com.arpa.ntocc.common.common.constant.StrConsts;
import com.arpa.ntocc.common.common.util.ShipmentWarehouseValidate;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.domain.dto.UserInfoDTO;
import com.arpa.ntocc.common.domain.dto.WarehouseAuthorizationJsonBean;
import com.arpa.ntocc.common.domain.entity.Party;
import com.arpa.ntocc.common.domain.enums.PartyTypeEnum;
import com.arpa.ntocc.common.security.annotation.NeedLogin;
import com.arpa.ntocc.common.service.authorize.AuthorizeTokenService;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.cache.WarehouseShipmentCache;
import com.arpa.wms.domain.consts.CodeConst;
import com.arpa.wms.domain.consts.CommonConst;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.consts.TipConst;
import com.arpa.wms.domain.dto.AllocationDTO;
import com.arpa.wms.domain.entity.Allocation;
import com.arpa.wms.domain.entity.WarehouseShipment;
import com.arpa.wms.domain.enums.AllocationStatusEnum;
import com.arpa.wms.domain.vo.AllocationVO;
import com.arpa.wms.domain.vo.WarehouseVO;
import com.arpa.wms.service.IAllocationService;
import com.arpa.wms.service.IWarehouseShipmentService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.arpa.ntocc.common.domain.dto.UserInfoDTO.AUTHORIZE_WAREHOUSE_CODES;


/**
 * <p>
 * WMS调拨单 Controller
 * </p>
 *
 * @author LEO
 * @since 2020-11-17
 */
@Api(tags = "WMS调拨单")
@RestController
@RequestMapping(value = "/allocation", produces = "application/json;charset=UTF-8")
@Log4j2
public class AllocationController {

    @Autowired
    private IAllocationService allocationService;

    @Autowired
    private AuthorizeTokenService authorizeTokenService;

    @Autowired
    private WarehouseCache warehouseCache;


    @Autowired
    private IWarehouseShipmentService warehouseShipmentService;

    @Autowired
    private WarehouseShipmentCache warehouseShipmentCache;



    /**
     * 获取 WMS调拨单 列表
     *
     * @param allocationDTO
     * @return
     */
    @ApiOperation(value = "获取 WMS调拨单 列表", notes = "获取 WMS调拨单 列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = AllocationVO.class))
    @NeedLogin
    @GetMapping()
    public Result list(AllocationDTO allocationDTO) {
        try {
            //校验授权仓库code和货主code不能为空
             Map<String, List<String>> authMap = ShipmentWarehouseValidate.validateShipmentCodesAndWarehouseCodes();
            //通过登录授权的仓库
            allocationDTO.setWarehouseCodes(authMap.get(CommonConst.WAREHOUSE_CODES));

            //登录仓库授权的货主过滤
            allocationDTO.setShipmentCodes(authMap.get(CommonConst.SHIPMENT_CODES));
            allocationDTO.setGroupCode(UserUtil.getBranchCode());
            log.info("查询调拨单入参 >>> {}", allocationDTO);
            AllocationVO allocationVosum = allocationService.queryListSum(allocationDTO);
            log.info("查询调拨单返回总数 >>> {}", allocationVosum.getTotal());
            List<AllocationVO> allocationVOList = allocationService.queryList(allocationDTO);
            log.info("查询调拨单列表数据 >>> {}", allocationVOList);

            Page returnPage = new Page(allocationDTO.getPageNum(), allocationDTO.getPageSize());
            returnPage.setRecords(allocationVOList);
            returnPage.setTotal(allocationVosum.getTotal());
            returnPage.setSumObject(allocationVosum);
            log.info("查询调拨单列表返回数据returnPage >>> {}", returnPage);
            return Result.ok().data(returnPage);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE, e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 添加 WMS调拨单
     *
     * @param entity Allocation
     * @return
     */
    @ApiOperation(value = "添加 WMS调拨单 ", notes = "添加 WMS调拨单 ")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PostMapping()
    public Result create(@RequestBody @Validated(Allocation.Save.class) Allocation entity) {
        try {
            log.info("添加WMS调拨单入参 >>> {}", entity);
            boolean flag = allocationService.save(entity);
            if (flag) {
                return Result.ok(TipConst.ADDED_SUCCESSFULLY);
            } else {
                return Result.error(TipConst.FAILED_TO_SAVE_DATA);
            }
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE, e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 获取WMS调拨单详情
     *
     * @param code
     * @return
     */
    @ApiOperation(value = "获取WMS调拨单详情", notes = "获取WMS调拨单详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer 123456"),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000"),
            @ApiImplicitParam(name = "code", value = "WMS调拨单code", paramType = "path", dataType = "String")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = Allocation.class))
    @NeedLogin
    @GetMapping(value = "/{code}")
    public Result allocation(@PathVariable String code) {
        try {
            log.info("获取WMS调拨单详情入参code >>> {}", code);
            AllocationVO entity = allocationService.getOneByCode(code);
            log.info("查询到的WMS调拨单详情entity >>> {}", entity);
            return Result.ok().data(entity);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE, e);
            return Result.error(e.getMessage());
        }
    }


    /**
     * 修改WMS调拨单
     *
     * @param entity WMS调拨单
     * @return
     */
    @ApiOperation(value = "修改WMS调拨单", notes = "修改WMS调拨单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping()
    public Result update(@RequestBody @Validated(Allocation.Update.class) Allocation entity) {
        log.info("修改WMS调拨单入参 >>> {}", entity);
        if (StringUtils.isBlank(entity.getCode())) {
            return Result.error(CodeConst.CODE + TipConst.NOT_BLANK);
        }
        int updateNum = allocationService.updateByCode(entity);
        if (updateNum == 0) {
            return Result.error("没有更新数据！code:" + entity.getCode());
        } else {
            return Result.ok("修改成功,更新" + updateNum + "条数据！");
        }
    }

    /**
     * 作废调拨单
     *
     * @param code
     * @return
     */
    @ApiOperation(value = "作废调拨单", notes = "作废调拨单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @PutMapping(value = "/invalid")
    public Result invalid(@RequestParam String code) {
        log.info("作废调拨单入参 >>> {}", code);
        if (StrUtil.isBlank(code)) {
            return Result.error(TipConst.CODE_NOT_EMPTY);
        }
        int updateNum = allocationService.updateStatusByCode(code, AllocationStatusEnum.INVALID.getValue());
        if (updateNum == 0) {
            return Result.error(code + "作废失败!");
        } else {
            return Result.ok(code + "作废成功!");
        }
    }



    /**
     * 获取 调拨单 审核列表
     *
     * @param dto
     * @return
     */
    @ApiOperation(value = "获取 调拨单 审核列表", notes = "获取 调拨单 审核列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer "),
            @ApiImplicitParam(name = "deviceId", value = "设备id", paramType = "header", dataType = "string", defaultValue = "0000000000")
    })
    @NeedLogin
    @GetMapping("/auditList")
    public Result auditList(AllocationDTO dto) {
        try {
            //校验授权仓库code和货主code不能为空
             Map<String, List<String>> authMap = ShipmentWarehouseValidate.validateShipmentCodesAndWarehouseCodes();
            //通过登录选择的仓库过滤数据
            dto.setWarehouseCodes(authMap.get(CommonConst.WAREHOUSE_CODES));
            //登录仓库授权的货主过滤
            dto.setShipmentCodes(authMap.get(CommonConst.SHIPMENT_CODES));
            dto.setGroupCode(UserUtil.getBranchCode());
            // 前端传的审核状态为空的话，则只查询“待审核”、“审核不通过”、“审核通过”的数据
            if (StrUtil.isBlank(dto.getAuditStatus())) {
                List<String> auditStatus = Arrays.asList(NumConst.NUM_ONE.toString(), NumConst.NUM_TWO.toString(), NumConst.NUM_THREE.toString());
                String auditStatusStr = auditStatus.stream().map(c -> StrUtil.wrap(c, "'")).collect(Collectors.joining(","));
                dto.setAuditStatus(auditStatusStr);
            }

            AllocationVO allocationVO = allocationService.auditListSum(dto);
            List<AllocationVO> allocationVos = allocationService.auditList(dto);

            Page returnPage = new Page(dto.getPageNum(), dto.getPageSize());
            returnPage.setRecords(allocationVos);
            returnPage.setTotal(allocationVO.getTotal());
            returnPage.setSumObject(allocationVO);
            return Result.ok().data(returnPage);
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE, e);
            return Result.error(e.getMessage());
        }
    }


    /**
     * WMS调拨单获取可调入仓库数据
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "WMS调拨单获取可调入仓库数据", notes = "WMS调拨单获取可调入仓库数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Authorization", value = "授权token", required = true, paramType = "header", dataType = "String", defaultValue = "Bearer ")
    })
    @ApiResponses(@ApiResponse(code = 0, message = "success", response = WarehouseVO.class))
    @NeedLogin
    @GetMapping("/targetWarehouses")
    public Result targetWarehouses(@RequestParam String shipmentCode,
                                   HttpServletRequest request) {
        return Result.ok().data(UserUtil.getAuthorizeWarehouseList());
       /* try {
            UserInfoDTO userInfoDTO = authorizeTokenService.getUserInfo();
            Map<String, Object> authorizeData = userInfoDTO.getAuthorizeData();
            Party party = userInfoDTO.getParty();
            if (party.getPartyType().equals(PartyTypeEnum.PLAT_ADMIN) || party.getPartyType().equals(PartyTypeEnum.SUPER_ADMIN)) {
                // 获取货主-仓库关联关系
                List<Object> w = warehouseShipmentService.list(
                        new QueryWrapper<WarehouseShipment>()
                                .lambda()
                                .eq(WarehouseShipment::getGroupCode,UserUtil.getBranchCode())
                        .eq(WarehouseShipment::getShipmentCode, shipmentCode)
                ).stream().map(WarehouseShipment::getWarehouseCode)
                        .map(r -> warehouseCache.get(r)).collect(Collectors.toList());


                return Result.ok().data(w);
            } else {
                if (MapUtil.isNotEmpty(authorizeData)) {
                    String warehouseAuthorization = MapUtil.getStr(authorizeData, AUTHORIZE_WAREHOUSE_CODES);
                    if (StrUtil.isNotBlank(warehouseAuthorization)) {
                        String[] warehouseAuthorizationArr = warehouseAuthorization.split(",");
                        List<String> warehouseCodes = Lists.newArrayList();
                        for (String warehouseCode : warehouseAuthorizationArr) {
                            if (null != warehouseShipmentCache.getShipment(warehouseCode, shipmentCode)) {
                                warehouseCodes.add(warehouseCode);
                            }
                        }
                        List<Object> w = warehouseCodes != null ? warehouseCodes.stream().map(r -> warehouseCache.get(r)).collect(Collectors.toList()) : null;
                        return Result.ok().data(w);
                    }
                }
            }
            return Result.ok();
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE, e);
            return Result.error(e.getMessage());
        }*/
    }

}
